package com.mrd.mina;

import android.content.Intent;

import com.mrd.dolphin.net.mina.codec.PbCodecFactory;
import com.yuerlive.rainbow.API;
import com.yuerlive.rainbow.utils.L;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by xiaoyi on 2017/5/25.
 */

public class MinaHelper {
    private String TAG = "MinaHelper";
    private IoSession mSession;
    private boolean isConnected = false;
    private Map<String, MinaCallback> callbacks = new HashMap<>();
    private Object lock = new Object();

    public void connect(MinaCallback callback, boolean connect) {
        if (callback != null)
            addCallback(callback);
        try {

            if (!isConnected && connect) {

                NioSocketConnector connector = new NioSocketConnector(2);

                //创建接受数据的过滤器
                DefaultIoFilterChainBuilder chain = connector.getFilterChain();

                //设定这个过滤器将一行一行(/r/n)的读取数据
                //chain.addLast("myChin", new ProtocolCodecFilter(new TextLineCodecFactory()));
                chain.addLast("codec", new ProtocolCodecFilter(new PbCodecFactory()));

                //客户端的消息处理器：一个SamplMinaServerHander对象
                connector.setHandler(new MinaClientHandler());

                //set connect timeout
                connector.setConnectTimeoutMillis(7000);

                //连接到服务器：
                ConnectFuture cf = connector.connect(new InetSocketAddress(API.LONG_HOST, API.TCP_PORT));

                //Wait for the connection attempt to be finished.
                cf.awaitUninterruptibly();

                cf.getSession().getCloseFuture().awaitUninterruptibly();

                connector.dispose();
            }

            if (isConnected) {
                callback.onConnected(mSession);
            }
        } catch (Exception e) {
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            connect(null, true);
            onException(null, e);
        }

    }

    private void addCallback(MinaCallback callback) {
        L.e(TAG,"callback  addCallback " +callback);
        synchronized (callbacks) {
            callbacks.put(String.valueOf(callback.hashCode()), callback);
        }
//        L.e(TAG, "callbacks " + callbacks);
    }

    public void removeCallback(MinaCallback callback) {
        L.e(TAG,"before remove " +callbacks);
        if (callbacks.containsKey(String.valueOf(callback.hashCode()))) {
           callbacks.remove(String.valueOf(callback.hashCode()));
        }

        L.e(TAG,"after remove " + callbacks);
    }

    public void removeAll() {
        callbacks.clear();
    }

    private Timer timer;

    private TimerTask task = null;

    private MinaHelper() {
    }

    private static volatile MinaHelper mInstance;

    public static MinaHelper getInstance() {
        if (mInstance == null) {
            synchronized (MinaHelper.class) {
                if (mInstance == null) {
                    mInstance = new MinaHelper();
                }
            }
        }
        return mInstance;
    }

    class HeartBeatTask extends TimerTask {
        @Override
        public void run() {
            if (mSession != null) {
                IoBuffer buffer = IoBuffer.allocate(24).setAutoExpand(true);
                buffer.putInt(0);
                buffer.putInt(1);
                buffer.putLong(System.currentTimeMillis());
                buffer.putInt(0);
                buffer.putInt(0);
                buffer.flip();
                mSession.write(buffer);
            }
        }
    }

    public void startHeartBeat() {
        timer = new Timer();
        task = new HeartBeatTask();
        timer.schedule(task, 300, 1000 * 60);
    }

    public void release() {
        if (timer != null) {

            timer.cancel();
            timer = null;
        }
        if (task != null) {
            task.cancel();
            //task = null;
        }
    }

    public void disConnected() {
        if (mSession != null)
            mSession.close(true);
        removeAll();
        release();
    }

    //回调
    void onConnected(IoSession session) {
        L.e(TAG, "onConnected");
        mSession = session;
        isConnected = true;
        startHeartBeat();
        for (Map.Entry<String, MinaCallback> entry : callbacks.entrySet()) {
            entry.getValue().onConnected(session);
        }
    }

    void onException(IoSession session, Throwable cause) {
        L.e(TAG, "onException");
        for (Map.Entry<String, MinaCallback> entry : callbacks.entrySet()) {
            entry.getValue().onException(session, cause);
        }
    }

    void onReceiveMessage(IoSession session, Object message) {
        L.e(TAG, "onReceiveMessage");
        for (Map.Entry<String, MinaCallback> entry : callbacks.entrySet()) {
            entry.getValue().onReceiveMessage(session, message);
        }
    }

    void onDisconnected(IoSession session) {
        L.e(TAG, "onDisconnected");
        isConnected = false;
        for (Map.Entry<String, MinaCallback> entry : callbacks.entrySet()) {
            entry.getValue().onDisConnected(session);
        }
        connect(null,true);
    }

    public void sendMessageToServer(Object message) {
        L.e(TAG, "sendMessageToServer");
        if (isConnected && mSession != null) {
            mSession.write(message);
        }
    }
}
